#include <iostream>
#include "Poco/SharedLibrary.h"
#include "Poco/Exception.h"
#include "DllLoader.h"

using namespace SystemTool;

// Construct the loader
DllLoader::DllLoader() : m_pLoader(new Poco::SharedLibrary)
{
    
}

// Construct the loader
DllLoader::DllLoader(std::string strDllFileName) : m_pLoader(new Poco::SharedLibrary)
{
    Load(strDllFileName);
}

// Destruct the loader
DllLoader::~DllLoader()
{
    Poco::SharedLibrary* pLoader = (Poco::SharedLibrary*)m_pLoader;
    if(pLoader)
    {
        delete pLoader;
        m_pLoader = nullptr;
    }
}

// Load the library
bool DllLoader::Load(std::string strDllFileName)
{
    if(strDllFileName.empty())
    {
        return false;
    }

    if(IsLoaded())
    {
        UnLoad();
    }

    Poco::SharedLibrary* pLoader = (Poco::SharedLibrary*)m_pLoader;
    if(pLoader == nullptr)
    {
        return false;
    }
    try
    {
        pLoader->load(strDllFileName);
    }
    catch(Poco::LibraryAlreadyLoadedException& e)
    {
        std::cout << "Dll is already existed" << std::endl;
        return true;
    }
    catch(Poco::Exception& e)
    {
        std::cout << "Failed to load dll:" << e.displayText() << std::endl;
        return false;
    }
    
    return true;
}

// Unload the library
void DllLoader::UnLoad()
{
    Poco::SharedLibrary* pLoader = (Poco::SharedLibrary*)m_pLoader;
    if(pLoader)
    {
        pLoader->unload();
    }
}

// Is library loaded
bool DllLoader::IsLoaded()
{
    Poco::SharedLibrary* pLoader = (Poco::SharedLibrary*)m_pLoader;
    if(pLoader == nullptr)
    {
        return false;
    }
    return pLoader->isLoaded();
}

// Get export function
void* DllLoader::GetExportFunc(std::string strFuncName)
{
    if(strFuncName.empty())
    {
        return nullptr;
    }
    Poco::SharedLibrary* pLoader = (Poco::SharedLibrary*)m_pLoader;
    if(pLoader == nullptr)
    {
        return nullptr;
    }
    void* pFunc = nullptr;
    try
    {
        pFunc = pLoader->getSymbol(strFuncName);
    }
    catch(Poco::Exception& e)
    {
        std::cout << "Failed to get func:" << e.displayText() << std::endl;
    }
    return pFunc;
}
